package com.hfzy.ihk.common.util.http;


import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.CharsetUtils;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Created by Administrator on 2016/5/12.
 * 基于httpClient4.5.2
 *
 */
@Component
public final class HttpClientUtils implements InitializingBean{

    private final static int HTTP_CLIENT_MAX_TOTAL =2000;
    private final static int HTTP_CLIENT_DEFAULT_MAX_PER_ROUTE =2000;

    private static RequestConfig requestConfig = null;

    private static PoolingHttpClientConnectionManager cm = null;

    private static CloseableHttpClient httpclient = null;

    private static IdleConnectionMonitorThread idleConnectionMonitorThread = null;

    public static void init(){

        requestConfig = RequestConfig.custom()
                .setSocketTimeout(30000)
                .setConnectTimeout(30000)
                .setConnectionRequestTimeout(120000)
                .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
                .build();

        System.out.println("init PoolingHttpClientConnectionManager start");

        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .register("http", PlainConnectionSocketFactory.getSocketFactory())//客户端直接连接到目标主机或者只通过了一个中间代理，这种就是Plain路由
                .build();

        /*PoolingHttpClientConnectionManager维护的连接数在每个路由基础和总数上都有限制。
        默认，每个路由基础上的连接不超过2个，总连接数不能超过20。在实际应用中，
        这个限制可能会太小了，尤其是当服务器也使用Http协议时。
        1、MaxtTotal是整个池子的大小；

        2、DefaultMaxPerRoute是根据连接到的主机对MaxTotal的一个细分；比如：

        MaxtTotal=400 DefaultMaxPerRoute=200

        而我只连接到http://sishuok.com时，到这个主机的并发最多只有200；而不是400；

        而我连接到http://sishuok.com 和 http://qq.com时，到每个主机的并发最多只有200；即加起来是400（但不能超过400）；
        所以起作用的设置是DefaultMaxPerRoute。
        */
        cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        // 整个连接池最大连接数
        cm.setMaxTotal(HTTP_CLIENT_MAX_TOTAL);
        // 每个路由到主机的最大并行链接数（只有一个路由，让他等于最大值）
        cm.setDefaultMaxPerRoute(HTTP_CLIENT_DEFAULT_MAX_PER_ROUTE);

        System.out.println("init PoolingHttpClientConnectionManager over."+cm);

        httpclient = HttpClients.custom()
                .setConnectionManager(cm)//采用连接池方式
                .build();

        idleConnectionMonitorThread = new IdleConnectionMonitorThread(cm);
        idleConnectionMonitorThread.start();

        System.out.println("init httpClient pool over!");
    }

    public static void destory(){

        requestConfig = null;
        try {
            httpclient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        httpclient = null;

        idleConnectionMonitorThread.shutdown();

        System.out.println("destory httpClient over!");
    }


    public static String postWithJson(String url, String json) throws Exception {

        String resValue = null;
        HttpEntity reqEntity = null;
        CloseableHttpResponse response = null;
        // 创建httppost
        HttpPost httppost = new HttpPost(url);
        // 创建参数队列

      //  try {
            StringEntity requestEntity = new StringEntity(json,"utf-8");
            requestEntity.setContentType("application/json");
            requestEntity.setContentEncoding("UTF-8");

            httppost.setHeader("Content-Type", "application/json;charset=UTF-8");
            httppost.setEntity(requestEntity);
            httppost.setConfig(requestConfig);
//            httppost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,false);
            response = httpclient.execute(httppost);

            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    resValue = EntityUtils.toString(entity, "UTF-8");
                    EntityUtils.consume(entity);
                }
            } finally {
                response.close();
            }
//        } catch (ClientProtocolException e) {
//            e.printStackTrace();
//        } catch (UnsupportedEncodingException e1) {
//            e1.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        return resValue;
    }




    public static String postMethod(String url, Map<String,String> params, File file) {

        String resValue = null;
        HttpEntity reqEntity = null;
        CloseableHttpResponse response = null;

        // 创建httppost
        HttpPost httppost = new HttpPost(url);
        // 创建参数队列

        // 创建默认的httpClient实例.
//        CloseableHttpClient httpclient = HttpClients.createDefault();

        try {
            if(file != null){

                MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
                        .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                        .addPart("uploadFile", new FileBody(file))
                        .setCharset(CharsetUtils.get("UTF-8"))
                        .setContentType(ContentType.MULTIPART_FORM_DATA);

                for(String key : params.keySet()) {
                    multipartEntityBuilder.addPart(key,new StringBody(params.get(key), ContentType.TEXT_PLAIN));
                }

                reqEntity = multipartEntityBuilder.build();

            }else{

                List<NameValuePair> formparams = new ArrayList<NameValuePair>();

                for(String key : params.keySet()) {
                    formparams.add(new BasicNameValuePair(key, params.get(key)));
                }
                reqEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
            }

            httppost.setEntity(reqEntity);
            httppost.setConfig(requestConfig);
            httppost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,false);

            response = httpclient.execute(httppost);

            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    resValue = EntityUtils.toString(entity, "UTF-8");
                    EntityUtils.consume(entity);
                }
            } finally {
                response.close();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return resValue;
    }

    public static String postMethodUploadFile(String url,  Map<String,String> params,String fileName, File file) {

        String resValue = null;
        HttpEntity reqEntity = null;
        CloseableHttpResponse response = null;

        // 创建httppost
        HttpPost httppost = new HttpPost(url);
        // 创建参数队列

        try {
            ContentType contentType = ContentType.create("multipart/form-data", Consts.UTF_8);

            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
                    .setCharset(Consts.UTF_8)
                    .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                    .addPart(fileName, new FileBody(file))
                    .setContentType(contentType);

            for(String key : params.keySet()) {
                multipartEntityBuilder.addPart(key,new StringBody(params.get(key), ContentType.TEXT_PLAIN));
            }

            reqEntity = multipartEntityBuilder.build();


            httppost.setEntity(reqEntity);
            httppost.setConfig(requestConfig);
            httppost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,false);

            response = httpclient.execute(httppost);

            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    resValue = EntityUtils.toString(entity, "UTF-8");
                    EntityUtils.consume(entity);
                }
            } finally {
                response.close();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return resValue;
    }

    public static String postMethodUploadFileList(String url, Map<String,String> params ,List<UploadFileList> list) {

        String resValue = null;
        HttpEntity reqEntity = null;
        CloseableHttpResponse response = null;

        // 创建httppost
        HttpPost httppost = new HttpPost(url);
        // 创建参数队列

        try {
            ContentType contentType = ContentType.create("multipart/form-data", Consts.UTF_8);

            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
                    .setCharset(Consts.UTF_8)
                    .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                    .setContentType(contentType);

                    for(UploadFileList file : list){
                        multipartEntityBuilder.addPart(file.getFileName(),new FileBody(file.getFile()));
                    }

            for(String key : params.keySet()) {
                multipartEntityBuilder.addPart(key,new StringBody(params.get(key), ContentType.TEXT_PLAIN));
            }

            reqEntity = multipartEntityBuilder.build();


            httppost.setEntity(reqEntity);
            httppost.setConfig(requestConfig);
            httppost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,false);

            response = httpclient.execute(httppost);

            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    resValue = EntityUtils.toString(entity, "UTF-8");
                    EntityUtils.consume(entity);
                }
            } finally {
                response.close();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return resValue;
    }


    public static String uploadFile(String url,String fileKey,File file) {

        String resValue = null;
        HttpEntity reqEntity = null;
        CloseableHttpResponse response = null;

        // 创建httppost
        HttpPost httppost = new HttpPost(url);
        // 创建参数队列

        try {
            ContentType contentType = ContentType.create("multipart/form-data", Consts.UTF_8);

            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
                    .setCharset(Consts.UTF_8)
                    .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                    .setContentType(contentType)
                    .addPart(fileKey,new FileBody(file));

            reqEntity = multipartEntityBuilder.build();

            httppost.setEntity(reqEntity);
            httppost.setConfig(requestConfig);
            httppost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,false);

            response = httpclient.execute(httppost);

            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    resValue = EntityUtils.toString(entity, "UTF-8");
                    EntityUtils.consume(entity);
                }
            } finally {
                response.close();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return resValue;
    }
    public static String uploadFileList(String url, Map<String,String> params ,Map<String,File> fileParams) {

        String resValue = null;
        HttpEntity reqEntity = null;
        CloseableHttpResponse response = null;

        // 创建httppost
        HttpPost httppost = new HttpPost(url);
        // 创建参数队列

        try {
            ContentType contentType = ContentType.create("multipart/form-data", Consts.UTF_8);

            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
                    .setCharset(Consts.UTF_8)
                    .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                    .setContentType(contentType);

            for(String key : params.keySet()) {
                multipartEntityBuilder.addPart(key,new StringBody(params.get(key), ContentType.TEXT_PLAIN));
            }
            for(String fileKey:fileParams.keySet()){
                multipartEntityBuilder.addPart(fileKey,new FileBody(fileParams.get(fileKey)));
            }

            reqEntity = multipartEntityBuilder.build();

            httppost.setEntity(reqEntity);
            httppost.setConfig(requestConfig);
            httppost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE,false);

            response = httpclient.execute(httppost);

            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    resValue = EntityUtils.toString(entity, "UTF-8");
                    EntityUtils.consume(entity);
                }
            } finally {
                response.close();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return resValue;
    }



    public static String getMethod(String url) {

        String resValue = null;
        CloseableHttpResponse response = null;

//        CloseableHttpClient httpclient = HttpClients.createDefault();

        try {

            // 创建httpget.
            HttpGet httpget = new HttpGet(url);

            httpget.setConfig(requestConfig);

            // 执行get请求.
            response = httpclient.execute(httpget);

            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    resValue = EntityUtils.toString(entity, "UTF-8");
                    EntityUtils.consume(entity);
                }
            } finally {
                response.close();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return resValue;

    }

    @Override
    public void afterPropertiesSet() throws Exception {
        init();
    }

    /*建立一个监控线程，来专门回收由于长时间不活动而被判定为失效的连接。
    这个监控线程可以周期性的调用ClientConnectionManager类的closeExpiredConnections()方法来关闭过期的连接，
    回收连接池中被关闭的连接。它也可以选择性的调用ClientConnectionManager类的closeIdleConnections()方法来关闭一段时间内不活动的连接。*/
    public static class IdleConnectionMonitorThread extends Thread {

        private final HttpClientConnectionManager connMgr;
        private volatile boolean shutdown;

        public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) {
            super();
            this.connMgr = connMgr;
        }

        @Override
        public void run() {
            try {
                while (!shutdown) {
                    synchronized (this) {
                        wait(30000);
                        // 关闭失效的连接
                        connMgr.closeExpiredConnections();
                        // 可选的, 关闭30秒内不活动的连接
                        connMgr.closeIdleConnections(120, TimeUnit.SECONDS);
                    }
                }
            } catch (InterruptedException ex) {
                // terminate
                System.out.println("IdleConnectionMonitorThread InterruptedException.");
            }
        }

        public void shutdown() {
            shutdown = true;
            synchronized (this) {
                notifyAll();
            }
        }

    }
}
